module sidearm.symtab;

import std.stdio;
import std.stdint;
import std.string;


string fullSymbolTypeToString(SymbolType t)
{
	return typeof(t).stringof ~ "." ~ toString(t);
}

// this is more for the lexer
enum SymbolType
{
	Unknown, Char, Digit, Special, EOF, EOL
}

// Symbol information below is in the context of a <symbol>
// at the source level of assembly not the lexer level
enum SymbolValueType {
	Byte, UByte, Word, UWord, Short, Int, UInt,
	String, Float, Double, Char, WChar, DChar
}

union SymbolValue {
	byte b;
	ubyte ub;
	uint16_t uw;
	int16_t w;
	uint24_t s;
	int32_t i;
	uint32_t ui;
	string s;
	float f;
	double d;
	char c;
	wchar wc;
	dchar dc;
}

struct Symbol
{
	string name = "";
	SymbolType type = SymbolType.Unknown;
	SymbolValueType vtype = SymbolValueType.Int;
	uint id = 0;
	SymbolValue val;
	bool bDefined = false;
	ubyte linerefs[5];
	uint24_t loc = 0;

	this(string n, SymbolType t, SymbolValueType vt, uint24_t l, uint i=0)
	{
		name = n;
		type = t;
		vtype = vt;
		if (i) id = i;
		loc = l;
	}


	string toString()
	{
		return
			"%s( %s,%s,%d )".format(typeof(this).stringof,
				  name.escapeDDQS(),
				  fullSymbolTypeToString(type),
				  id
			  );
	}
}

// most common hash symtab algo used by ELF files
ulong defaultSymtabHash(const ubyte * name)
{
	ulong h = 0, g;

	while(*name)
	{
		h = (h<<4)+*name++;
		if (g = h & 0xf0000000)
			h ^= g >> 24;
		h &= ~g;
	}
	return h;
}
/+++ SymbolTable
 +
 +/
class SymbolTable
{
public:
	void print()
	{

	}

	uint enter(Symbol s)
	{
		if (_find(s.name)) {
			// update symbol reference?
		} else {
			s.id = _genID();
			_symbols[s.name] = s;
		}
		return s.id;
	}

	@property const string name() { return _name; }



private:
	ref Symbol _find(string n) {
		try
		{
			auto s = _symbols[n];
		} catch (core.exception.RangeError e)
		{
			return null;
		}
		return s;
	}
	ref Symbol _find(uint i) {
		try
		{
			// TODO	

		} catch (core.exception.RangeError e)
		{
			return null;
		}
		return s;
	}

	static _genID() { return __base_id++; }

	static uint __base_id = 0;
	string _name;
	Symbol[string] _symbols;
}